import json
import logging
import os
import threading
import time

import requests
from flask import Flask, request, jsonify

from raft.static.cluster import HEART_BEAT_INTERVAL
from raft.static.log_entity import LogEntity
from raft.static.raft_node import RaftNode

logging.basicConfig(format='%(asctime)s - %(levelname)s: %(message)s', datefmt='%H:%M:%S', level=logging.INFO)
raft_node_id = int(os.environ.get('NODE_ID'))
raft_node = RaftNode(raft_node_id)


def create_app():
    raft = Flask(__name__)
    raft_node.start()
    return raft


app = create_app()


@app.route('/raft/vote', methods=['POST'])
def request_vote():
    vote_request = request.get_json()
    result = raft_node.vote(json.loads(vote_request))
    return jsonify(result)


@app.route('/raft/heartbeat', methods=['POST'])
def heartbeat():
    logging.info(f'{raft_node.id} got heartbeat from leader: {raft_node.leader_id}')
    request_data = request.get_json()
    b_commit, term = raft_node.append_entries(request_data)
    d = {"id": raft_node.id, "alive": True, 'log_commit_state': b_commit, 'node_state': raft_node.node_state,
         'term': term}
    # raft_node.become_follower()
    return jsonify(d)


@app.route('/raft/read', methods=['GET'])
def read():
    logging.info(f'{raft_node.id} got read command from client')
    log = []
    for item in raft_node.entity:
        log.append(item.get_json())
    read_data = {
        'raft_id': raft_node.id,
        'raft_url': raft_node.node.url,
        'raft_term': raft_node.current_term,
        'raft_logs': log
    }
    return jsonify(read_data)


@app.route('/raft/write', methods=['POST'])
def write():
    write_json = request.get_json()
    logging.info(f'{raft_node.id} got write command from client')
    if raft_node.node_state != 'leader':
        logging.info(f'{raft_node.id} is not follower, it redirect leader')
        response = requests.post(f'http://{raft_node.leader_url}/raft/write', json=write_json)
        return jsonify(response)
    else:
        log = LogEntity(raft_node.match_index + 1, raft_node.current_term, raft_node.leader_id, write_json['info'])
        raft_node.entity.append(log)
        for peer in [peer for peer in raft_node.cluster if peer != raft_node.node]:
            raft_node.entity_dict[peer.id] = raft_node.get_entity_dict(log.get_json())
        response = '写入成功'
        return jsonify(response)


if __name__ == '__main__':
    create_app()
    app.run()
